package com.voip.sipphone;

import sun.net.sdp.SdpSupport;

import javax.sdp.SdpException;
import javax.sdp.SdpFactory;
import javax.sip.*;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.*;


public class SipLayer implements SipListener {
    public MessageProcessor messageProcessor;
    public String username;
    public SipStack sipStack;
    public SipFactory sipFactory;
    public SdpFactory sdpFactory;
    public AddressFactory addressFactory;
    public HeaderFactory headerFactory;
    public MessageFactory messageFactory;
    public SipProvider sipProvider;

    public static SipLayer listener;

    protected Dialog dialog;
    /**
     * 主叫对话
     */
    protected Dialog calleeDialog = null;
    /**
     * 被叫对话
     */
    protected Dialog callerDialog = null;

    protected ClientTransaction clientTransaction;
    protected SipPhoneHelper sipPhoneHelper;
    protected ServerTransaction serverTransactionId;

    /**
     * Here we initialize the SIP stack.
     */
    public SipLayer(String username, String ip, int port)
            throws PeerUnavailableException, TransportNotSupportedException, InvalidArgumentException, ObjectInUseException, TooManyListenersException {
        setUsername(username);
        sipFactory = SipFactory.getInstance();
        sipFactory.setPathName("gov.nist");
        Properties properties = new Properties();
        properties.setProperty("javax.sip.STACK_NAME", "SipPhoneLayer");
        properties.setProperty("javax.sip.IP_ADDRESS", ip);
        properties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "32");
        properties.setProperty("gov.nist.javax.sip.SERVER_LOG", "textclient.txt");
        properties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "textclientdebug.log");
        //事务不结束
        properties.setProperty("gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS", "false");
        sipStack = sipFactory.createSipStack(properties);

        headerFactory = sipFactory.createHeaderFactory();
        addressFactory = sipFactory.createAddressFactory();
        messageFactory = sipFactory.createMessageFactory();

       // ListeningPoint tcp1 = sipStack.createListeningPoint("127.0.0.1", port, "tcp");
      //  ListeningPoint udp1 = sipStack.createListeningPoint("127.0.0.1", port, "udp");
         ListeningPoint tcp = sipStack.createListeningPoint(port, "tcp");
         ListeningPoint udp = sipStack.createListeningPoint(port, "udp");


        sipProvider = sipStack.createSipProvider(tcp);
        sipProvider.addSipListener(this);
        sipProvider = sipStack.createSipProvider(udp);
        sipProvider.addSipListener(this);

        listener = this;
        sipPhoneHelper = new SipPhoneHelper(sipStack, sipFactory
                , addressFactory, headerFactory, messageFactory, sipProvider, listener);

    }



    /**
     * 处理sip请求返回 response
     * This method is called by the SIP stack when a response arrives.
     */
    public void processResponse(ResponseEvent responseReceivedEvent) {

        System.out.println("Got a response");
        Response response = (Response) responseReceivedEvent.getResponse();
        CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);

        System.out.println("Response received : Status Code = "
                + response.getStatusCode() + " " + cseq);

        try {
            if (cseq.getMethod().equals(Request.REGISTER)) {
                sipPhoneHelper.processRegisterResponse(responseReceivedEvent);
            } else if (cseq.getMethod().equals(Request.INVITE)) {
                Invite.processInviteResponse(responseReceivedEvent);
            } else if (cseq.getMethod().equals(Request.BYE)) {
                // processByeResponse(responseReceivedEvent);
            } else {
                System.out.println("Response to unexpected request");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    /**
     * This method is called by the SIP stack when a new request arrives.
     */
    public void processRequest(RequestEvent requestReceivedEvent) {

        Request request = requestReceivedEvent.getRequest();

        if (null == request) {
            System.out.println("processRequest request is null.");
            return;
        }
        if (Request.BYE.equalsIgnoreCase(request.getMethod())) {
            sipPhoneHelper.processByeResponse(request, requestReceivedEvent);
        }
        System.out.println(requestReceivedEvent);
    }


    /**
     * This method is called by the SIP stack when there's no answer to a   * message. Note that this is treated differently from an error message.
     */
    public void processTimeout(TimeoutEvent evt) {
        System.out.println("processTimeout");
        messageProcessor.processError("Previous message not sent: " + "timeout");
    }

    /**
     * This method is called by the SIP stack when there's an asynchronous   * message transmission error.
     */
    public void processIOException(IOExceptionEvent evt) {
        System.out.println("processIOException");
        messageProcessor.processError("Previous message not sent: " + "I/O Exception");
    }

    /**
     * This method is called by the SIP stack when a dialog (session) ends.
     */
    public void processDialogTerminated(DialogTerminatedEvent evt) {
        System.out.println("processDialogTerminated");
        System.out.println("processDialogTerminated " + evt.toString());
    }

    /**
     * This method is called by the SIP stack when a transaction ends.
     */
    public void processTransactionTerminated(TransactionTerminatedEvent evt) {
        System.out.println("processTransactionTerminated");
    }


    public String getHost() {
        String host = sipStack.getIPAddress();
        return host;
    }

    public int getPort() {
        int port = 5060;
        ListeningPoint[] listeningPoints = sipProvider.getListeningPoints();
        for (int i = 0; i < listeningPoints.length; i++) {
            if (listeningPoints[i] != null) {
                port = listeningPoints[i].getPort();
            }
        }
        return port;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String newUsername) {
        username = newUsername;
    }

    public MessageProcessor getMessageProcessor() {
        return messageProcessor;
    }

    public void setMessageProcessor(MessageProcessor newMessageProcessor) {
        messageProcessor = newMessageProcessor;
    }


    public void processInvite(String s) {
        try {
            sipPhoneHelper.processInvite("13250333247");
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (InvalidArgumentException e) {
            e.printStackTrace();
        } catch (SipException e) {
            e.printStackTrace();
        } catch (SdpException e) {
            e.printStackTrace();
        }
    }
}